﻿using System.Buffers;
using System.Collections.Concurrent;
using System.Net.WebSockets;
using System.Text;
using System.Text.Json;

using GCC.Container.Abstracts;

namespace GCC.APIContainer.WSManager
{
    /// <summary>
    /// 容器的websocket池
    /// </summary>
    internal class GCCTextWSPool
    {
        /// <summary>
        /// ws池单例
        /// </summary>
        public static readonly GCCTextWSPool Instance = new();
        /// <summary>
        /// 接收登陆的缓冲池
        /// </summary>
        private readonly MemoryPool<byte> _memPool = MemoryPool<byte>.Shared;

        /// <summary>
        /// 当用户链接事件
        /// </summary>
        public event Action? OnConnectionChanged;
        private readonly JsonSerializerOptions _jsonOPT;

        /// <summary>
        /// 默认构造
        /// </summary>
        private GCCTextWSPool()
        {
            _jsonOPT = new JsonSerializerOptions(LuanNiao.JsonConverterExtends.CommonSerializerOptions.CamelCaseChineseNameCaseInsensitive);
            _jsonOPT.Converters.Add(new LuanNiao.JsonConverterExtends.DateTime2StringConverter("yyyy-MM-dd HH:mm"));
            _jsonOPT.Converters.Add(new LuanNiao.JsonConverterExtends.Long2StringConverter());
        }

        /// <summary>
        /// 所有的字符串ws对象池
        /// </summary>
        private readonly ConcurrentDictionary<long, List<GCCTextWSInfo>> _infoPool = new();

        ///// <summary>
        ///// 链接
        ///// </summary>
        ///// <param name="context">当前的上下文</param>
        ///// <param name="webSocket">websocket对象</param>
        ///// <returns></returns>
        //public async Task<GCCTextWSInfo?> OnConnect(AbsGCCContext context, WebSocket webSocket)
        //{
        //    using var loginBufferOwner = _memPool.Rent(1024);
        //    var loginBuffer = loginBufferOwner.Memory[..1024];
        //    var result = await webSocket.ReceiveAsync(loginBuffer, CancellationToken.None);
        //    if (result.EndOfMessage == false)
        //    {
        //        return null;
        //    }
        //    var loginRequest = System.Text.Json.JsonSerializer.Deserialize<GCCWSLoginRequest>(Encoding.UTF8.GetString(loginBuffer[..result.Count].Span), _jsonOPT);

        //    if (loginRequest is null)
        //    {
        //        return null;
        //    }
        //    var userInfo = await context.GetUserByToken(loginRequest.Token);
        //    if (userInfo is null)
        //    {
        //        return null;
        //    }
        //    var thisInstance = new GCCTextWSInfo(context, webSocket)
        //    {
        //        Type = loginRequest.ClientType ?? "PC"
        //    };
        //    thisInstance.OnDisposing += (id) =>
        //    {
        //        _ = _infoPool.AddOrUpdate(userInfo.UID, (key) =>
        //        {
        //            var res = new List<GCCTextWSInfo>();
        //            return res;
        //        }, (key, old) =>
        //        {
        //            var item = old.FirstOrDefault(item => item.ID == id);
        //            if (item is not null)
        //            {
        //                _ = old.Remove(item);
        //            }
        //            return old;
        //        });
        //        OnConnectionChanged?.Invoke();
        //    };
        //    _ = _infoPool.AddOrUpdate(userInfo.UID, (key) =>
        //    {
        //        var res = new List<GCCTextWSInfo>();
        //        res.Add(thisInstance);
        //        return res;
        //    }, (key, old) =>
        //    {
        //        old.Add(thisInstance);
        //        return old;
        //    });
        //    var responseInfo = new GCCWSLoginResponse()
        //    {
        //        ClientType = thisInstance.Type,
        //        Token = thisInstance.ID,
        //        Type = "LoginCompleted"
        //    };

        //    var loginResult = JsonSerializer.Serialize(responseInfo, _jsonOPT);
        //    _ = webSocket.SendAsync(Encoding.UTF8.GetBytes(loginResult), WebSocketMessageType.Text, true, CancellationToken.None);
        //    OnConnectionChanged?.Invoke();
        //    return thisInstance;
        //}


        /// <summary>
        /// tcm链接
        /// </summary>
        /// <param name="context">当前的上下文</param>
        /// <param name="webSocket">websocket对象</param>
        /// <returns></returns>
        public async Task<GCCTextWSInfo?> TCMOnConnect(AbsGCCContext context, WebSocket webSocket)
        {
            using var loginBufferOwner = _memPool.Rent(1024);
            var loginBuffer = loginBufferOwner.Memory[..1024];
            var result = await webSocket.ReceiveAsync(loginBuffer, CancellationToken.None);
            if (result.EndOfMessage == false)
            {
                return null;
            }
            var tCMDeviceRequest = System.Text.Json.JsonSerializer.Deserialize<TCMDeviceRequest>(Encoding.UTF8.GetString(loginBuffer[..result.Count].Span), _jsonOPT);
            if (tCMDeviceRequest is null ||tCMDeviceRequest.site_id<=0)
            {
                return null;
            }

            var user = context.TryGet<LoginUser>(tCMDeviceRequest.token).Result;
            if (user is null)
            {
                return null;
            }

            _=context.Remove(tCMDeviceRequest.site_id.ToString());
            context.Set<TCMDeviceRequest>(tCMDeviceRequest.site_id.ToString(), tCMDeviceRequest, new CacheItemSettings()
            {
                SaveToAll = true,
                SlidingExpiration = TimeSpan.FromSeconds(60*60*2),
            }).Wait();

            var thisInstance = new GCCTextWSInfo(context, webSocket)
            {
                Type = "PC"
            };
            thisInstance.OnDisposing += (id) =>
            {
                _ = _infoPool.AddOrUpdate(tCMDeviceRequest.site_id, (key) =>
                {
                    var res = new List<GCCTextWSInfo>();
                    return res;
                }, (key, old) =>
                {
                    var item = old.FirstOrDefault(item => item.ID == id);
                    if (item is not null)
                    {
                        _ = old.Remove(item);
                    }
                    return old;
                });
                OnConnectionChanged?.Invoke();
            };
            _ = _infoPool.AddOrUpdate(tCMDeviceRequest.site_id, (key) =>
            {
                var res = new List<GCCTextWSInfo>();
                res.Add(thisInstance);
                return res;
            }, (key, old) =>
            {
                old.Add(thisInstance);
                return old;
            });
            var responseInfo = new GCCWSLoginResponse()
            {
                ClientType = thisInstance.Type,
                Token = thisInstance.ID,
                Type = "LoginCompleted"
            };

            var loginResult = JsonSerializer.Serialize(responseInfo, _jsonOPT);
            _ = webSocket.SendAsync(Encoding.UTF8.GetBytes(loginResult), WebSocketMessageType.Text, true, CancellationToken.None);
            OnConnectionChanged?.Invoke();
            return thisInstance;
        }

        /// <summary>
        /// 获取所有的在线用户ID
        /// </summary>
        /// <returns></returns>
        public List<long> GetAllUserID()
        {     
            return this._infoPool.Where(p => p.Value.Count>0).Select(p => p.Key).ToList();
        }

        /// <summary>
        /// 获取用户的链接列表
        /// </summary>
        /// <param name="uid">用户ID</param>
        /// <returns></returns>
        public List<GCCTextWSInfo> GetUserTextWSInfo(long uid)
        { 
            if (_infoPool.TryGetValue(uid, out var data))
            {
                return data;
            }
            return new List<GCCTextWSInfo>();
        }

        /// <summary>
        /// 給某个用户发送文本的消息
        /// </summary>
        /// <param name="uid">用户ID</param>
        /// <param name="text">文本</param>
        public void SendTextMessageToUser(long uid, string text)
        {
            if (_infoPool.TryGetValue(uid, out var info))
            {
                try
                {
                    info.ForEach(item =>
                    {
                        _ = Task.Run(() =>
                          {
                              item.SendTextMessage(text);
                          });
                    });
                }
                catch
                {

                }
            }
        }
        /// <summary>
        /// 給某个用户的某个端发送文本的消息
        /// </summary>
        /// <param name="uid">用户ID</param>
        /// <param name="clientID">用户clientID</param>
        /// <param name="text">文本</param>
        public void SendTextMessageToUserClient(long uid, string clientID, string text)
        {
            if (_infoPool.TryGetValue(uid, out var info))
            {
                try
                {
                    info.ForEach(item =>
                    {
                        if (item.ID == clientID)
                        {
                            _ = Task.Run(() =>
                            {
                                item.SendTextMessage(text);
                            });
                        }
                    });
                }
                catch
                {

                }
            }
        }

        /// <summary>
        /// 给所有在线的人光波
        /// </summary>
        /// <param name="text"></param>
        public void BoardCastTextMessage(string text)
        {
            try
            {
                this._infoPool.Values.ToList().ForEach(item =>
                {
                    try
                    {
                        item.ForEach(item =>
                        {
                            _ = Task.Run(() =>
                            {
                                item.SendTextMessage(text);
                            });
                        });
                    }
                    catch
                    {
                    }
                });
            }
            catch
            {

            }

        }

        /// <summary>
        /// 强制下线
        /// </summary>
        /// <param name="uid">用户ID</param>
        /// <param name="clientID">端ID不传就是全部</param>
        public void ForcedOffline(long uid, string? clientID)
        {
            if (_infoPool.TryGetValue(uid, out var info))
            {
                try
                {
                    info.ForEach(item =>
                    {
                        if (clientID is null)
                        {
                            _ = Task.Run(() =>
                            {
                                item.Dispose();
                            });
                        }
                        else if (item.ID == clientID)
                        {
                            _ = Task.Run(() =>
                            {
                                item.Dispose();
                            });
                        }
                    });
                }
                catch
                {

                }
            }
        }

    }
}
